#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
IR 类节点定义
"""

import ast
from dataclasses import dataclass, field
from typing import Any, Dict, List, Iterator, Optional
from ..base import IRNode
from ...symbol_table import (
    Symbol,
    SymbolKind,
)
from .method import IRMethodNode
from .property import IRPropertyNode


@dataclass
class IRClassNode(IRNode):
    """IR类节点"""

    name: str = field(default="")
    source_line: int = field(default=0)
    decorators: List[Dict[str, Any]] = field(default_factory=list)
    doc: str = field(default="")
    bases: List[str] = field(default_factory=list)
    methods: List["IRMethodNode"] = field(default_factory=list)
    properties: List["IRPropertyNode"] = field(default_factory=list)
    template_params: List[str] = field(
        default_factory=list
    )  # 模板参数：['T', 'K', 'V']

    # 类属性
    node_type: str = "class"

    def creates_scope(self) -> bool:
        """类节点创建作用域"""
        return True

    def get_child_nodes(self) -> Iterator["IRNode"]:
        """获取所有子节点"""
        # 方法节点
        for method in self.methods:
            yield method

        # 属性节点
        for prop in self.properties:
            yield prop

        yield from super().get_child_nodes()

    def get_method_by_access_mod(self, access_mod: str) -> List["IRMethodNode"]:
        """获取类的方法节点列表

        Args:
            access_mod: 访问修饰符

        Returns:
            方法节点列表
        """
        return [
            method
            for method in self.methods
            if isinstance(method, IRMethodNode) and method.access_modifier == access_mod
        ]

    def _should_be_static_member(self, item: ast.AnnAssign) -> bool:
        """判断类型注解的属性是否应该为静态成员

        Args:
            item: AST注解赋值节点

        Returns:
            是否应该为静态成员
        """
        # 如果没有初始值，则为实例成员
        if item.value is None:
            return False

        # 检查是否为@dataclass装饰的类
        is_dataclass = any(dec["name"] == "dataclass" for dec in self.decorators)

        if is_dataclass:
            # 对于@dataclass，检查初始值是否为field()调用
            if isinstance(item.value, ast.Call):
                if (
                    isinstance(item.value.func, ast.Name)
                    and item.value.func.id == "field"
                ):
                    # field()调用应该为实例成员
                    return False
            # @dataclass中的其他有初始值的属性也是实例成员
            return False

        # 非@dataclass的类，有初始值的类变量是静态的
        return True

    def get_propertie_by_access_mod(self, access_mod: str) -> List[IRPropertyNode]:
        """获取类的属性节点列表

        Args:
            access_mod: 访问修饰符

        Returns:
            属性节点列表
        """
        return [prop for prop in self.properties if prop.access_modifier == access_mod]

    def get_member_by_access_mod(
        self, access_mod: str
    ) -> List["IRMethodNode | IRPropertyNode"]:
        """获取类的属性和方法节点列表

        Args:
            access_mod: 访问修饰符

        Returns:
            属性节点列表
        """
        return self.get_method_by_access_mod(
            access_mod
        ) + self.get_propertie_by_access_mod(access_mod)

    def new_symbol(self) -> "Symbol":
        """创建类的符号"""
        # 获取所属模块信息
        ir_module = self.get_ir_module()
        module_name = ir_module.module_full_name if ir_module else None

        symbol = Symbol(
            name=self.name,
            kind=SymbolKind.CLASS,
            ir_node=self,
            module=module_name,
        )

        return symbol

    def get_local_symbols(self) -> Iterator[Symbol]:
        """获取类中定义的所有本地符号

        Returns:
            本地符号的迭代器
        """
        # 方法符号
        for method in self.methods:
            symbol = method.get_symbol()
            if symbol:
                yield symbol

        # 属性符号
        for prop in self.properties:
            symbol = prop.get_symbol()
            if symbol:
                yield symbol

    def _extract_template_params(self, slice_node: ast.expr) -> List[str]:
        """提取模板参数名称

        Args:
            slice_node: ast.Subscript的slice部分

        Returns:
            模板参数名列表，如 ['T'] 或 ['K', 'V']
        """
        params = []

        if isinstance(slice_node, ast.Name):
            # Generic[T] - 单个参数
            params.append(slice_node.id)
        elif isinstance(slice_node, ast.Tuple):
            # Generic[K, V] - 多个参数
            for elt in slice_node.elts:
                if isinstance(elt, ast.Name):
                    params.append(elt.id)

        return params

    def build_from_ast(self, node: ast.ClassDef) -> None:
        """从 AST 类定义节点构建 IR 类节点内容

        Args:
            node: AST 类定义节点
        """
        super().build_from_ast(node)

        # 提取基类名称和模板参数
        bases = []
        template_params = []

        for base in node.bases:
            if isinstance(base, ast.Name):
                bases.append(base.id)
            elif isinstance(base, ast.Attribute):
                # 处理 module.ClassName 形式的基类
                bases.append(ast.unparse(base))
            elif isinstance(base, ast.Subscript):
                # 处理 Generic[T], Protocol[T] 等泛型基类
                if isinstance(base.value, ast.Name):
                    base_name = base.value.id

                    # Generic是类型标记，不是真正的基类
                    if base_name == "Generic":
                        # 提取模板参数，但不加入bases
                        template_params = self._extract_template_params(base.slice)
                    else:
                        # 其他泛型基类（如Protocol[T]）
                        bases.append(base_name)

        self.template_params = template_params

        # 提取装饰器信息
        decorators = []
        for decorator in node.decorator_list:
            if isinstance(decorator, ast.Name):
                # 简单装饰器：@decorator_name
                decorators.append({"name": decorator.id, "args": [], "kwargs": {}})
            elif isinstance(decorator, ast.Call):
                # 带参数的装饰器：@decorator_name(args)
                decorator_name = ""
                if isinstance(decorator.func, ast.Name):
                    decorator_name = decorator.func.id
                elif isinstance(decorator.func, ast.Attribute):
                    decorator_name = ast.unparse(decorator.func)

                # 提取位置参数
                args = []
                for arg in decorator.args:
                    if isinstance(arg, ast.Constant):
                        args.append(arg.value)
                    else:
                        args.append(ast.unparse(arg))

                # 提取关键字参数
                kwargs = {}
                for keyword in decorator.keywords:
                    if isinstance(keyword.value, ast.Constant):
                        kwargs[keyword.arg] = keyword.value.value
                    else:
                        kwargs[keyword.arg] = ast.unparse(keyword.value)

                decorators.append(
                    {"name": decorator_name, "args": args, "kwargs": kwargs}
                )
            else:
                # 其他复杂装饰器形式
                decorators.append(
                    {"name": ast.unparse(decorator), "args": [], "kwargs": {}}
                )

        # 设置类节点属性
        self.name = node.name
        self.source_line = getattr(node, "lineno", 0)
        self.decorators = decorators
        self.bases = bases
        self.doc = ast.get_docstring(node) or ""

        # 处理类体中的方法和属性
        for item in node.body:
            if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)):
                # 创建方法节点
                method_node = IRMethodNode(
                    name=item.name, source_line=getattr(item, "lineno", 0), parent=self
                )
                method_node.build_from_ast(item)
                self.methods.append(method_node)
            elif isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
                # 处理类型注解的属性
                # 判断是否为静态成员
                is_static = self._should_be_static_member(item)
                prop_node = IRPropertyNode(
                    name=item.target.id,
                    source_line=getattr(item, "lineno", 0),
                    type_annotation=(
                        ast.unparse(item.annotation) if item.annotation else ""
                    ),
                    is_static=is_static,
                    parent=self,
                )
                prop_node.build_from_ast(item)
                self.properties.append(prop_node)
            elif (
                isinstance(item, ast.Assign)
                and len(item.targets) == 1
                and isinstance(item.targets[0], ast.Name)
            ):
                # 处理普通赋值语句作为类变量（静态成员）
                prop_node = IRPropertyNode(
                    name=item.targets[0].id,
                    source_line=getattr(item, "lineno", 0),
                    type_annotation="",  # 普通赋值没有类型注解，需要类型推导
                    is_static=True,  # 类级别的赋值被视为静态成员
                    parent=self,
                )
                # 为普通赋值创建一个临时的AnnAssign节点来复用现有逻辑
                # 创建一个虚拟的类型注解节点
                dummy_annotation = ast.Name(id="int", ctx=ast.Load())
                temp_ann_assign = ast.AnnAssign(
                    target=item.targets[0],
                    annotation=dummy_annotation,
                    value=item.value,
                    simple=1,
                )
                prop_node.build_from_ast(temp_ann_assign)
                self.properties.append(prop_node)
